package com.file.parser;

import com.file.bo.ResponseData;
import com.file.bo.mail.CQC;
import com.file.bo.mail.CQCTran;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import technology.tabula.*;
import technology.tabula.detectors.SpreadsheetDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 丰巢-重庆银行pdf解析类
 */
@Slf4j
public class CQCPdfParser extends BasePdfParser {

    public ResponseData<String> parseCQCPdfToJson(String daId, String filePath) {
        log.info("parseJSPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            CQC cqc = parseCQCPdf(filePath);
            json = JsonUtils.convertObjectToJson(cqc);
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseCQCPdfToJson failed", e);
            return new ResponseData<String>(json, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseCQCPdfToJson completed, daId:{}", daId);
        return new ResponseData<String>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    public CQC parseCQCPdf(String filePath) {
        CQC cqc = parseCQCHeader(filePath);
        List<CQCTran> cqcTrans = parseTrans(filePath);
        cqc.setCqcTrans(cqcTrans);
        return cqc;
    }

    public CQC parseCQCHeader(String filePath) {
        CQC cqc = new CQC();
        String pdfHeaderText = parsePdfHeaderText(filePath);
        String accountNo = pdfHeaderText.substring(pdfHeaderText.indexOf("账号:") + 3, pdfHeaderText.indexOf("序号")).replaceAll(" ", "");  //NOSONAR
        String id = pdfHeaderText.substring(pdfHeaderText.indexOf("序号:") + 3, pdfHeaderText.indexOf("币种:")).replaceAll(" ", "");  //NOSONAR
        String productType = pdfHeaderText.substring(pdfHeaderText.indexOf("产品类型:") + 5, pdfHeaderText.indexOf("起止日期")).replaceAll(" ", "");
        String transDetailPeriod = pdfHeaderText.substring(pdfHeaderText.indexOf("起止日期:") + 5, pdfHeaderText.indexOf("账户名称")).replaceAll(" ", "");//NOSONAR
        String accountName = pdfHeaderText.substring(pdfHeaderText.indexOf("账户名称:") + 5, pdfHeaderText.indexOf("① ② ③")).replaceAll(" ", "");  //NOSONAR
        String currency = pdfHeaderText.substring(pdfHeaderText.indexOf("币种:") + 3, pdfHeaderText.indexOf("产品类型")).replaceAll(" ", ""); //NOSONAR
        String availableBalanceOnInquiryDate = pdfHeaderText.substring(pdfHeaderText.indexOf("明细查询日可用余额 :") + 11, pdfHeaderText.indexOf("明细查询日账面余额")).replaceAll(" ", ""); //NOSONAR
        String detailInquiryDateBookBalance = pdfHeaderText.substring(pdfHeaderText.indexOf("明细查询日账面余额 :") + 11, pdfHeaderText.indexOf("明细截止日活期账面余额")).replaceAll(" ", ""); //NOSONAR
        String cutoffCurrentAccountBalance = pdfHeaderText.substring(pdfHeaderText.indexOf("明细截止日活期账面余额 :") + 12, pdfHeaderText.indexOf("交易 交易对手信息")).replaceAll(" ", ""); //NOSONAR
        String detailPeriodTotalIncome = pdfHeaderText.substring(pdfHeaderText.indexOf("明细期间总收入:") + 8, pdfHeaderText.indexOf("明细期间总支出")).replaceAll(" ", ""); //NOSONAR
        String detailPeriodTotalExpenditure = pdfHeaderText.substring(pdfHeaderText.indexOf("明细期间总支出:") + 8, pdfHeaderText.indexOf("明细期间总收入 - 明细期间总支出")).replaceAll(" ", ""); //NOSONAR
        String netIncomeDuringPeriod = pdfHeaderText.substring(pdfHeaderText.indexOf("- 明细期间总支出 =") + 11, pdfHeaderText.indexOf("打印时间:")).replaceAll(" ", ""); //NOSONAR
        String printTime = pdfHeaderText.substring(pdfHeaderText.indexOf("打印时间:") + 5, pdfHeaderText.indexOf("打印机构")).trim();//NOSONAR
        String printingInstitution = pdfHeaderText.substring(pdfHeaderText.indexOf("打印机构:") + 5, pdfHeaderText.indexOf("以上内容因不可预测")).trim();//NOSONAR

        cqc.setId(id);
        cqc.setProductType(productType);
        cqc.setAccountNo(accountNo);
        cqc.setAccountName(accountName);
        cqc.setCurrency(currency);
        cqc.setTransDetailPeriod(transDetailPeriod);
        cqc.setAvailableBalanceOnInquiryDate(availableBalanceOnInquiryDate);
        cqc.setDetailInquiryDateBookBalance(detailInquiryDateBookBalance);
        cqc.setCutoffCurrentAccountBalance(cutoffCurrentAccountBalance);
        cqc.setDetailPeriodTotalIncome(detailPeriodTotalIncome);
        cqc.setDetailPeriodTotalExpenditure(detailPeriodTotalExpenditure);
        cqc.setNetIncomeDuringPeriod(netIncomeDuringPeriod);
        cqc.setPrintTime(printTime);
        cqc.setPrintingInstitution(printingInstitution);
        return cqc;
    }

    private List<List<String>> parseFileToRowList(String filePath) {
        // 1. 读取文件
        File pdf = new File(filePath);

        //页面所有table的记录，每一个元素代表下面一条记录cellList
        List<List<String>> rowList = new ArrayList<>();

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            SpreadsheetDetectionAlgorithm detectionAlgorithm = new SpreadsheetDetectionAlgorithm();
            Map<Integer, List<Rectangle>> pageNumber2RectangleListMap = new HashMap<>();//key为页的序号， value为对应的Rectangle的list

            // 4. 获取每页的PageIterator
            PageIterator pageIterator = objectExtractor.extract();

            // 5. 解析每页的Rectangle
            // 如果单页pdf中有多个Rectangle，则解析出来的List<Rectangle>会有多个对象
            while (pageIterator.hasNext()) {
                Page page = pageIterator.next();
                List<Rectangle> rectangleList = detectionAlgorithm.detect(page);
                if (rectangleList.size() > 0) {
                    pageNumber2RectangleListMap.put(page.getPageNumber(), rectangleList);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm extractionAlgorithm = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : pageNumber2RectangleListMap.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());
                Rectangle rectangle = null;

                List<Rectangle> rectangleList = entry.getValue();
                for (Rectangle r : rectangleList) {
                    double rectangleHeight = r.getHeight();
                    if (Double.compare(rectangleHeight, 0) > 0 && Double.compare(r.getWidth(), 0) > 0) {
                        rectangle = r;
                        break;
                    }
                }
                if (rectangle == null) {
                    throw new RuntimeException("rectangle is null.");
                }

                if (entry.getKey() > 1) {
                    rectangle.setTop(rectangle.getTop());
                }
                rectangle.setBottom(rectangle.getBottom() + 50);
                Page area = page.getArea(rectangle);

                // 如果每页有多个表格，解析每一个table
                List<Table> tableList = extractionAlgorithm.extract(area);
                for (Table table : tableList) {
                    for (int i = 0; i < table.getRowCount(); i++) {
                        List<String> cellList = new ArrayList<>();//一条记录，每个单元格占一个元素
                        for (int j = 0; j < table.getColCount(); j++) {
                            cellList.add(table.getCell(i, j).getText(false));
                        }
                        rowList.add(cellList);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return rowList;
    }

    public String parsePdfHeaderText(String filePath) {
        String pdfHeaderText = "";
        try (PDDocument pdDocument = PDDocument.load(new File(filePath))) {
            PDFTextStripper stripper = new PDFTextStripper();
            stripper.setSortByPosition(true);
            int totalPages = pdDocument.getNumberOfPages(); // 获取总页数

            stripper.setStartPage(totalPages);
            stripper.setEndPage(totalPages);
            pdfHeaderText = stripper.getText(pdDocument);
            pdfHeaderText = pdfHeaderText.replace(System.getProperty("line.separator", "\n"), "");
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), "", "", "", "parsePdfHeaderText failed", e);
            throw new RuntimeException(e);
        }
        return pdfHeaderText;
    }

    public List<CQCTran> parseTrans(String filePath) {
        List<List<String>> rowList = parseFileToRowList(filePath);
        List<CQCTran> cqcTrans = new ArrayList<>();
        for (int i = 0; i < rowList.size(); i++) {
            if (StringUtils.containsAny(rowList.get(i).get(0), "序号")) {
                continue;
            }
            if (rowList.get(i).size() == 8 && rowList.get(i).get(0).matches("\\d+")) {
                CQCTran cqcTran = new CQCTran();
                cqcTran.setId(rowList.get(i).get(0));
                cqcTran.setTranDate(rowList.get(i).get(1));
                cqcTran.setTranAmt(rowList.get(i).get(2));
                cqcTran.setCurrentAccountBookBalance(rowList.get(i).get(3));
                cqcTran.setSummary(rowList.get(i).get(4));
                cqcTran.setAdditionalMessage(rowList.get(i).get(5));
                cqcTran.setCounterpartyInformation(rowList.get(i).get(6));
                cqcTran.setVoucherInformation(rowList.get(i).get(7));
                cqcTrans.add(cqcTran);
            }
        }
        return cqcTrans;
    }


    public static void main(String[] args) {
        CQCPdfParser pdfParser = new CQCPdfParser();
        CQC cqc;
        cqc = pdfParser.parseCQCPdf("D:\\data\\file\\beehive-cqc\\重庆银行交易流水.pdf");
        System.out.println(JsonUtils.convertObjectToJson(cqc));
        cqc = pdfParser.parseCQCPdf("D:\\data\\file\\beehive-cqc\\重庆银行交易明细-全.pdf");
        System.out.println(JsonUtils.convertObjectToJson(cqc));
    }

}
